package wps.mojo.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ClassUtils;

/**
 * @Author : <a href="mailto:Juanyong.zhang@carefirst.com">Cham
 *         Juanyong.zhang</a>
 * @Date : Apr 14, 2011
 */
public class ReflectionUtils {

	public static Method[] getAllMethods(Class<? extends Object> type,
			Class<? extends Annotation>... qualifieds) {
		Set<Method> ms = new HashSet<Method>();
		if (null != qualifieds && qualifieds.length > 0) {
			CollectionUtils.addAll(ms,
					getQualifiedMethods(type.getDeclaredMethods(), qualifieds));
		} else {
			CollectionUtils.addAll(ms, type.getDeclaredMethods());
		}

		Class<?> superType = type.getSuperclass();
		while (superType != null && !superType.equals(Object.class)) {

			if (null != qualifieds && qualifieds.length > 0) {
				CollectionUtils.addAll(
						ms,
						getQualifiedMethods(superType.getDeclaredMethods(),
								qualifieds));
			} else {
				CollectionUtils.addAll(ms, superType.getDeclaredMethods());
			}
			superType = superType.getSuperclass();
		}

		return ms.toArray(new Method[ms.size()]);
	}

	private static Method[] getQualifiedMethods(Method[] ms,
			Class<? extends Annotation>[] qualifieds) {
		Set<Method> qualifiedMs = new HashSet<Method>();
		for (Method m : ms) {
			for (Class<? extends Annotation> q : qualifieds) {
				if (null != m.getAnnotation(q)) {
					qualifiedMs.add(m);
				}
			}
		}
		return qualifiedMs.toArray(new Method[qualifiedMs.size()]);
	}

	public static Field[] getAllFields(Class<? extends Object> type,
			Class<? extends Annotation>... qualifieds) {
		Set<Field> fs = new HashSet<Field>();
		if (null != qualifieds && qualifieds.length > 0) {
			CollectionUtils.addAll(fs,
					getQualifiedFields(type.getDeclaredFields(), qualifieds));
		} else {
			CollectionUtils.addAll(fs, type.getDeclaredFields());
		}

		Class<?> superType = type.getSuperclass();
		while (superType != null && !superType.equals(Object.class)) {

			if (null != qualifieds && qualifieds.length > 0) {
				CollectionUtils.addAll(
						fs,
						getQualifiedFields(superType.getDeclaredFields(),
								qualifieds));
			} else {
				CollectionUtils.addAll(fs, superType.getDeclaredFields());
			}
			superType = superType.getSuperclass();
		}

		return fs.toArray(new Field[fs.size()]);
	}

	private static Field[] getQualifiedFields(Field[] fs,
			Class<? extends Annotation>[] qualifieds) {
		Set<Field> qualifiedFs = new HashSet<Field>();
		for (Field f : fs) {
			for (Class<? extends Annotation> q : qualifieds) {
				if (null != f.getAnnotation(q)) {
					qualifiedFs.add(f);
				}
			}
		}

		return qualifiedFs.toArray(new Field[qualifiedFs.size()]);
	}

	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		} catch (Throwable ex) {
		}
		if (cl == null) {
			cl = ClassUtils.class.getClassLoader();
		}
		return cl;
	}
}
